#ifndef ACAPELLA_THREAD_THREADBASIC_HPP
#define ACAPELLA_THREAD_THREADBASIC_HPP

#include <acapella/acapella.h>
#include <acapella/delegate/delegate.hpp>
#include "thread_traits.h"
#include "thread_impl.h"


namespace acapella
{
namespace thread
{

template<typename traits = thread_traits > 
class ThreadBasic
{
public:
	typedef typename traits::ThreadHandle ThreadHandle;
	typedef typename traits::ThreadParam ThreadParam;
	typedef typename traits::ThreadFunc ThreadFunc;
	typedef typename traits::ThreadImpl ThreadImpl;
	typedef typename traits::functor_type functor_type;

	typedef ThreadBasic<traits> SelfType;
	typedef int (*UserThreadFunc)(ThreadParam);

	static SelfType Current()
	{
		return Thread(ThreadImpl::Current());
	}

	static int Exit(_uint32_ retcode)
	{
		return ThreadImpl::Exit(retcode);
	}

	ThreadBasic()
		:needCleanup_(false)
	{

	}

    ThreadBasic(const functor_type& functor)
        :functor_(functor),needCleanup_(false)
    {
    }

	~ThreadBasic()
	{
		if (needCleanup_)
		{
			ThreadImpl::Cleanup(tHandle_);
		}
	}

	ThreadHandle GetHandle()
	{
		return tHandle_;
	}

	void SetUserFunction(functor_type userFunc)
	{
        functor_ = userFunc;
	}

	int Create(ThreadParam param, _uint32_ stackSize)
	{
		param_ = param;
		int result = ThreadImpl::Create(&tHandle_, stackSize, reinterpret_cast<ThreadFunc>
                (&ThreadBasic::threadFunc), this);
		if (result == 0)
		{
			needCleanup_ = true;
		}
		return result;
	}

	int Join(void ** rval_ptr)
	{
		return ThreadImpl::Join(tHandle_, rval_ptr);
	}

private:

	static _uint32_ STDCALL threadFunc(ThreadParam param)
	{
		ThreadBasic* self = (ThreadBasic*)param;

		int result = self->Call();

		return result;
	}

	int Call()
	{
		return (int)functor_((ThreadParam)param_);
	}
	

	ThreadHandle tHandle_;
	ThreadParam param_;
	functor_type functor_;
	bool needCleanup_;
};

}//namespace thread
}//namespace acapella

#endif
